package com.cloud.school.app.service.impl;

import com.cloud.school.app.entity.TbShow;
import com.cloud.school.app.mapstruct.IShowConvertMapper;
import com.cloud.school.app.model.CommentModel;
import com.cloud.school.app.model.ImageModel;
import com.cloud.school.app.model.ShowModel;
import com.cloud.school.app.model.UserModel;
import com.cloud.school.app.repository.TbShowMapper;
import com.cloud.school.app.service.*;
import com.cloud.school.app.util.IdWorker;
import com.cloud.school.app.util.Pager;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.cloud.school.app.config.CloudSchoolProperties.PAGE_PER_COUNT;
import static com.cloud.school.app.service.impl.CommentServiceImpl.USER_NEW_COMMENT;

/**
 * @ClassName ShowServiceImpl
 * @Description TODO
 * @Author 36297
 * @Date 2018/12/14 0:56
 * @Version 1.0
 */
@Service
public class ShowServiceImpl implements ShowService {

    @Autowired
    private TbShowMapper tbShowMapper;
    @Autowired
    private IShowConvertMapper showConvertMapper;
    @Autowired
    private IdWorker showIdWorker;
    @Autowired
    private CommentService commentService;
    @Autowired
    private LikeService likeService;
    @Autowired
    private UserService userService;
    @Autowired
    private ImageService imageService;
    @Autowired
    private CacheService cacheService;

    @Override
    public Pager<ShowModel> selectByUid(Long Uid, int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        TbShow show = new TbShow();
        show.setCreateUid(Uid);
        List<TbShow> shows = tbShowMapper.select(show);
        Pager result = Pager.build(shows);
        result.setResultList(showConvertMapper.entityToModel(shows));
        return result;
    }

    @Override
    public Pager<ShowModel> selectAll(int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        List<TbShow> shows = tbShowMapper.selectAll();
        Pager result = Pager.build(shows);
        result.setResultList(showConvertMapper.entityToModel(shows));
        return result;
    }

    @Override
    public Pager<ShowModel> selectDetailByUid(Long Uid, int pNo) {
        Pager<ShowModel> result = selectByUid(Uid, pNo);
        appendUser(result.getResultList());
        appendImage(result.getResultList());
        appendComment(result.getResultList());
        result.getResultList().forEach(s -> cacheService.hashDelete(USER_NEW_COMMENT + s.getCreateUid(), String.valueOf(s.getId())));
        return result;
    }

    @Override
    public Pager<ShowModel> selectDetailWithoutCommentFormatByUid(Long Uid, int pNo) {
        Pager<ShowModel> result = selectByUid(Uid, pNo);
        appendUser(result.getResultList());
        appendImage(result.getResultList());
        appendCommentWithoutFormat(result.getResultList());
        result.getResultList().forEach(s -> cacheService.hashDelete(USER_NEW_COMMENT + s.getCreateUid(), String.valueOf(s.getId())));
        return result;
    }

    @Override
    public Pager<ShowModel> selectAllDetail(int pNo) {
        Pager<ShowModel> result = selectAll(pNo);
        appendUser(result.getResultList());
        appendImage(result.getResultList());
        appendComment(result.getResultList());
        result.getResultList().forEach(s -> cacheService.hashDelete(USER_NEW_COMMENT + s.getCreateUid(), String.valueOf(s.getId())));
        return result;
    }

    @Override
    public Pager<ShowModel> selectAllDetailWithoutCommentFormat(int pNo) {
        Pager<ShowModel> result = selectAll(pNo);
        appendUser(result.getResultList());
        appendImage(result.getResultList());
        appendCommentWithoutFormat(result.getResultList());
        result.getResultList().forEach(s -> cacheService.hashDelete(USER_NEW_COMMENT + s.getCreateUid(), String.valueOf(s.getId())));
        return result;
    }

    @Override
    public ShowModel selectById(Long showId) {
        return showConvertMapper.entityToModel(tbShowMapper.selectByPrimaryKey(showId));
    }

    @Override
    public ShowModel selectDetailById(Long showId) {
        ShowModel result = selectById(showId);
        if (result == null) {
            return null;
        }
        List<ShowModel> showModels = Lists.newArrayList(result);
        appendUser(showModels);
        appendImage(showModels);
        appendComment(showModels);
        cacheService.hashDelete(USER_NEW_COMMENT + result.getCreateUid(), String.valueOf(result.getId()));
        return result;
    }

    @Override
    public ShowModel selectDetailWithoutCommentFormatById(Long showId) {
        ShowModel result = selectById(showId);
        if (result == null) {
            return null;
        }
        List<ShowModel> showModels = Lists.newArrayList(result);
        appendUser(showModels);
        appendImage(showModels);
        appendCommentWithoutFormat(showModels);
        cacheService.hashDelete(USER_NEW_COMMENT + result.getCreateUid(), String.valueOf(result.getId()));
        return result;
    }

    private void appendUser(List<ShowModel> result) {
        List<Long> uids = result.stream().map(s -> s.getCreateUid()).filter(id -> id != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(uids)) {
            Map<Long, UserModel> userModelMap = userService.queryDetailByIds(uids).stream().collect(Collectors.toMap(UserModel::getId, u -> u));
            result.forEach(showModel -> showModel.setCreator(userModelMap.get(showModel.getCreateUid())));
        }
    }

    private void appendImage(List<ShowModel> result) {
        List<Long> imageIds = result.stream().map(s -> s.getImages()).flatMap(images -> images.stream()).filter(id -> id != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(imageIds)) {
            Map<Long, ImageModel> imageModelMap = imageService.seleteByIds(imageIds).stream().collect(Collectors.toMap(ImageModel::getId, i -> i));
            result.forEach(showModel -> showModel.setImageModels(getByIdsString(imageModelMap, showModel.getImages())));
        }
    }

    private void appendComment(List<ShowModel> result) {
        List<Long> showIds = result.stream().map(s -> s.getId()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(showIds)) {
            List<CommentModel> commentModels = commentService.queryDetailByShowIds(showIds);
            result.forEach(showModel -> showModel.setCommentModels(commentListFormat(commentModels).get(showModel.getId())));
        }
    }

    private void appendCommentWithoutFormat(List<ShowModel> result) {
        List<Long> showIds = result.stream().map(s -> s.getId()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(showIds)) {
            Map<Long, List<CommentModel>> longListMap = commentService.queryDetailByShowIds(showIds).stream().collect(Collectors.groupingBy(CommentModel::getShowId));
            result.forEach(showModel -> showModel.setCommentModels(longListMap.get(showModel.getId())));
        }
    }

    private Map<Long, List<CommentModel>> commentListFormat(List<CommentModel> commentModels) {
        Map<Long, List<CommentModel>> longCommentMListMap = commentModels.stream().filter(c -> c.getPrevId() != null).collect(Collectors.groupingBy(c -> c.getPrevId()));
        Map<Long, CommentModel> longCommentModelMap = commentModels.stream().collect(Collectors.toMap(c -> c.getId(), c -> c));
        longCommentMListMap.forEach((k, v) -> Optional.ofNullable(longCommentModelMap.get(k)).ifPresent(c -> c.setCommentModels(v)));
        return commentModels.stream().filter(c -> c.getPrevId() == null).collect(Collectors.groupingBy(c -> c.getShowId()));
    }

    private List<ImageModel> getByIdsString(Map<Long, ImageModel> imageModelMap, List<Long> ids) {
        List<ImageModel> list = Lists.newArrayList();
        ids.forEach(id -> list.add(imageModelMap.get(id)));
        return list;
    }

    @Override
    @Transactional
    public boolean save(ShowModel showModel) {
        TbShow show = showConvertMapper.modelToEntity(showModel);
        show.setId(showIdWorker.nextId());
        show.setCreateTime(System.currentTimeMillis());
        return tbShowMapper.insertSelective(show) > 0;
    }

    @Override
    @Transactional
    public boolean deleteById(Long showId) {
        ShowModel showModel = selectById(showId);
        if (showModel != null && showModel.getImages() != null) {
            showModel.getImages().forEach(id -> imageService.delete(id));
        }
        likeService.deleteByShowId(showId);
        commentService.deleteByShowId(showId);
        cacheService.hashDelete(USER_NEW_COMMENT + showModel.getCreateUid(), String.valueOf(showModel.getId()));
        return tbShowMapper.deleteByPrimaryKey(showId) > 0;
    }
}
